/*
 * Time.h
 *
 *  Created on: Jun 12, 2013
 *      Author: Lucifer
 */

#ifndef TIME_H_
#define TIME_H_

#include <sys/timeb.h>
#include <limits.h>

#ifdef	_WIN32

#ifndef __LONG_LONG_MAX__
#define __LONG_LONG_MAX__ 9223372036854775807LL
#endif

#ifndef	LONG_LONG_MIN
#define LONG_LONG_MIN (-LONG_LONG_MAX-1)
#define LONG_LONG_MAX __LONG_LONG_MAX__
#endif	//	LONG_LONG_MIN

#endif

#define	__CLAMP(v, l, h)	((v) < (l)) ? (l) : (((v) > (h)) ? (h) : (v))

namespace BFX
{

////////////////////////////////////////////////////////////////////////////////

/**
 * This class represents a duration of time.
 */
class TimeSpan
{
public:
	/**
	 * Initializes a zero BFX::TimeSpan instance.
	 */
	TimeSpan();

	/**
	 * Initializes a new BFX::TimeSpan instance to the specified of time span value.
	 * @param lTime The time span value based on microseconds.
	 */
	TimeSpan(INT64 lTime);

	/**
	 * The copy constructor initializes a new BFX::TimeSpan instance to the others.
	 * @param ts
	 */
	TimeSpan(const TimeSpan& ts);

	/**
	 * Gets a value that represents the number of complete days.
	 * @return The number of complete 24-hour days in the time span. This value may be negative if the time span is
	 * 		negative.
	 */
	int GetDays() const;

	/**
	 * Gets a value that represents the number of hours in the current day.
	 * @return The number of hours in the current day (-23 through 23).
	 */
	int GetHours() const;

	/**
	 * Gets a value that represents the number of minutes in the current hour.
	 * @return The number of minutes in the current hour (-59 through 59).
	 */
	int GetMinutes() const;

	/**
	 * Gets a value that represents the number of seconds in the current minute.
	 * @return The number of seconds in the current minute (-59 through 59).
	 */
	int GetSeconds() const;

	/**
	 * Gets a value that represents the number of milliseconds  in the current seconds.
	 * @return the number of milliseconds in the current second (-1000 through 1000).
	 */
	int GetMilliseconds() const;

	/**
	 * Gets a value that represents the total number of complete hours.
	 * @return The total number of complete hours.
	 */
	INT64 GetTotalHours() const;

	/**
	 * Gets a value that represents the total number of complete minutes.
	 * @return The total number of complete minutes.
	 */
	INT64 GetTotalMinutes() const;

	/**
	 * Gets a value that represents the total number of complete seconds.
	 * @return The total number of complete seconds.
	 */
	INT64 GetTotalSeconds() const;

	/**
	 * Gets a value that represents the total number of complete milliseconds.
	 * @return The total number of complete milliseconds.
	 */
	INT64 GetTotalMilliseconds() const;

	//
	// Operators
	//

	/**
	 * The assign constructor to sets the specified BFX::TimeSpan instance to this instance.
	 * @param ts The BFX::TimeSpan instance to be set.
	 * @return The reference of this instance.
	 */
	TimeSpan& operator =(const TimeSpan& ts);

	/**
	 * Adds the specified BFX::TimeSpan instance to this instance.
	 * @param ts The BFX::TimeSpan instance to be add.
	 * @return The result BFX::TimeSpan instance.
	 */
	TimeSpan& operator +=(const TimeSpan& ts);

	/**
	 * Subtracts the specified TimeSpan to this instance.
	 * @param ts The BFX::TimeSpan instance to be subtract.
	 * @return The result BFX::TimeSpan instance.
	 */
	TimeSpan& operator -=(const TimeSpan& ts);


	/**
	 * Adds two specified BFX::TimeSpan instances.
	 * @param ts The another specified BFX::TimeSpan instance.
	 * @return The result BFX::TimeSpan instance.
	 */
	TimeSpan operator +(const TimeSpan& ts);

	/**
	 * Subtracts the current TimeSpan instance from another specified TimeSpan instance.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return The result BFX::TimeSpan instance.
	 */
	TimeSpan operator -(const TimeSpan& ts);

	/**
	 * Tests whether two BFX::TimeSpan instances are equal.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the values are equal; otherwise, false.
	 */
	bool operator ==(const TimeSpan& ts) const;

	/**
	 * Tests whether two BFX::TimeSpan instances are not equal.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the values are not equal; otherwise, false.
	 */
	bool operator !=(const TimeSpan& ts) const;

	/**
	 * Tests whether a specified TimeSpan is greater than another specified TimeSpan.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the current value is greater than the value of ts; otherwise, false.
	 */
	bool operator >(const TimeSpan& ts) const;

	/**
	 * Tests whether a specified BFX::TimeSpan instance is greater than or equal to another specified BFX::TimeSpan
	 * instance.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the current value is greater than or equal to the value of ts; otherwise, false.
	 */
	bool operator >=(const TimeSpan& ts) const;

	/**
	 * Tests whether a specified BFX::TimeSpan instance is less than another specified BFX::TimeSpan instance.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the current value is less than the value of ts; otherwise, false.
	 */
	bool operator <(const TimeSpan& ts) const;

	/**
	 * Tests whether a specified BFX::TimeSpan instance is less than or equal to another specified BFX::TimeSpan
	 * instance.
	 * @param ts The another BFX::TimeSpan instance.
	 * @return True if the current value is less than or equal to the value of ts; otherwise, false.
	 */
	bool operator <=(const TimeSpan& ts) const;

	//
	// Static constructors
	//

	/**
	 * Represents the zero BFX::TimeSpan value.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan Zero();

	/**
	 * Gets a BFX::TimeSpan instance that represents a specified number of days.
	 * @param lDays A number of days.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan FromDays(INT64 lDays);

	/**
	 * Gets a BFX::TimeSpan instance that represents a specified number of hours.
	 * @param lHours A number of hours.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan FromHours(INT64 lHours);

	/**
	 * Gets a BFX::TimeSpan instance that represents a specified number of minutes.
	 * @param lMinutes A number of minutes.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan FromMinutes(INT64 lMinutes);

	/**
	 * Gets a BFX::TimeSpan instance that represents a specified number of seconds.
	 * @param lSeconds A number of seconds.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan FromSeconds(INT64 lSeconds);

	/**
	 * Gets a BFX::TimeSpan instance that represents a specified number of milliseconds.
	 * @param lMilliseconds A number of milliseconds.
	 * @return The BFX::TimeSpan instance.
	 */
	static TimeSpan FromMilliseconds(INT64 lMilliseconds);

private:
	friend class Time;
	static INT64 TimeToTicks(int nHour, int nMinute, int nSecond);

	static TimeSpan Interval(INT64 value, INT64 scale);

private:
	static const INT64 TicksPerMillisecond = 1000;
	static const INT64 TicksPerSecond = TicksPerMillisecond * 1000;
	static const INT64 TicksPerMinute = TicksPerSecond * 60;
	static const INT64 TicksPerHour = TicksPerMinute * 60;
	static const INT64 TicksPerDay = TicksPerHour * 24;

	INT64 m_lTicks;			// microseconds
};

////////////////////////////////////////////////////////////////////////////////

/**
 * Represents an absolute time and date.
 */
class Time
{
public:
	/**
	 * Initializes a new instance of the BFX::Time of current time.
	 */
	Time();

	/**
	 * Initializes a new instance of the BFX::Time with specified ticks.
	 * @param ticks
	 */
	Time(INT64 ticks);

	/**
	 * Initializes a new instance of the BFX::Time with specified ticks, local time-zone.
	 * @param ticks
	 * @param lTimezone
	 */
	Time(INT64 ticks, long lTimezone);

	/**
	 * Initializes a new instance of the BFX::Time with the specified year, month, and day.
	 * @param nYear
	 * @param nMonth
	 * @param nDay
	 */
	Time(int nYear, int nMonth, int nDay);

	/**
	 * Initializes a new instance of the BFX::Time with the specified year, month, day, and time-zone.
	 * @param nYear
	 * @param nMonth
	 * @param nDay
	 * @param lTimezone
	 */
	Time(int nYear, int nMonth, int nDay, long lTimezone);

	/**
	 * Initializes a new instance of the BFX::Time with the specified year, month, day, hour, minute, and second.
	 * @param nYear
	 * @param nMonth
	 * @param nDay
	 * @param nHour
	 * @param nMinute
	 * @param nSecond
	 */
	Time(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond);

	/**
	 * Initializes a new instance of the BFX::Time with the specified year, month, day, hour, minute, second, and time-zone.
	 * @param nYear
	 * @param nMonth
	 * @param nDay
	 * @param nHour
	 * @param nMinute
	 * @param nSecond
	 * @param lTimezone
	 */
	Time(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond, long lTimezone);

	/**
	 * The copy constructor to initializes a new instance of the BFX::Time from other instance.
	 * @param time
	 */
	Time(const Time& time);

	/**
	 * The destructor to destroys the BFX::Time instance.
	 */
	virtual ~Time();

	static Time MinValue();

	static Time MaxValue();

	/**
	 * Creates a BFX::Time instance that represents the current time.
	 * @return the new instance of BFX::Time.
	 */
	static Time Now();

	/**
	 * Creates a BFX::Time instance that is set to the current time, expressed as the Coordinated Universal Time (UTC).
	 * @return the new instance of BFX::Time.
	 */
	static Time UtcNow();

	/**
	 * Converts the value of the current BFX::Time object to local time.
	 * @return The local time.
	 */
	Time ToLocalTime() const;
	/**
	 * Converts the value of the current BFX::Time object to UTC time.
	 * @return The UTC time.
	 */
	Time ToUtcTime() const;

	/**
	 * Retrieves the current system universal time (UTC).
	 * @return the current system UTC format date and time, in microseconds.
	 */
	static INT64 GetSysUtcTicks();

	/**
	 * Retrieves current system universal (UTC) time-zone.
	 * @return Difference in seconds between local time and UTC. The default value is 28800 (28800 seconds equals 8 hours)
	 *
	 */
	static long GetSysTimeZone();

	/**
	 * Gets a ticks value for the current BFX::Time instance.
	 * @return The number of ticks that represent the date and time of this instance.
	 */
	INT64 GetTicks() const;

	INT64 GetUtcTicks() const;

	/**
	 * Gets the year component of the date represented by this instance.
	 * @return
	 */
	int GetYear() const;

	/**
	 * Gets the month of the year represented by this instance.
	 * @return
	 */
	int GetMonth() const;

	/**
	 * Gets the day of the month represented by this instance.
	 * @return
	 */
	int GetDay() const;

	/**
	 * Gets the hour of the day represented by this instance.
	 * @return
	 */
	int GetHour() const;

	/**
	 * Gets the minute of the hour represented by this instance.
	 * @return
	 */
	int GetMinute() const;

	/**
	 * Gets the second of the minute represented by this instance.
	 * @return
	 */
	int GetSecond() const;

	/**
	 * Gets the millisecond of the second represented by this instance.
	 * @return
	 */
	int GetMillisecond() const;

	/**
	 * The assign constructor to sets this BFX::Time instance from other instance.
	 * @param time
	 * @return
	 */
	Time& operator =(const Time& time);

	/**
	 * Adds the this BFX::Time instance with specified BFX::TimeSpan instances.
	 * @param ts
	 * @return
	 */
	Time operator +(const TimeSpan& ts) const;

	/**
	 * Subtracts the this BFX::Time instance with specified BFX::TimeSpan instances.
	 * @param ts
	 * @return
	 */
	Time operator -(const TimeSpan& ts) const;

	/**
	 * Subtracts this BFX::Time instance with specified another BFX::Time instances.
	 * @param time
	 * @return
	 */
	TimeSpan operator -(const Time& time) const;

	/**
	 * Adds the specified BFX::TimeSpan instance to this BFX::Time instance.
	 * @param ts
	 * @return
	 */
	Time& operator +=(const TimeSpan& ts);

	/**
	 * Subtracts the specified BFX::TimeSpan instance from this BFX::Time instance.
	 * @param ts
	 * @return
	 */
	Time& operator -=(const TimeSpan& ts);

	/**
	 * Tests whether this BFX::Time instance is equal to the another instance.
	 * @param time
	 * @return
	 */
	bool operator ==(const Time& time) const;

	/**
	 * Tests whether this BFX::Time instance is not equal to the another instance.
	 * @param time
	 * @return
	 */
	bool operator !=(const Time& time) const;

	/**
	 * Tests whether this BFX::Time instance is greater then the another instance.
	 * @param time
	 * @return
	 */
	bool operator >(const Time& time) const;

	/**
	 * Tests whether this BFX::Time instance is greater then or equal to the another instance.
	 * @param time
	 * @return
	 */
	bool operator >=(const Time& time) const;

	/**
	 * Tests whether this BFX::Time instance is less then the another instance.
	 * @param time
	 * @return
	 */
	bool operator <(const Time& time) const;

	/**
	 * Tests whether this BFX::Time instance is less then or equal to the another instance.
	 * @param time
	 * @return
	 */
	bool operator <=(const Time& time) const;

private:
    // Return the tick count corresponding to the given year, month, day, hour, minute, second. Will check the if the
	// parameters are valid.
	static INT64 TimeToTicks(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond);

	// Checks whether a given year is a leap year. This method
	// returns true if year is a leap year, or false if not.
	static bool IsLeapYear(int nYear);

	int GetDatePart(int part) const;

private:
	// Number of 100ns ticks per time unit
	static const INT64 TicksPerMillisecond = 1000;
	static const INT64 TicksPerSecond = TicksPerMillisecond * 1000;
	static const INT64 TicksPerMinute = TicksPerSecond * 60;
	static const INT64 TicksPerHour = TicksPerMinute * 60;
	static const INT64 TicksPerDay = TicksPerHour * 24;

	// Number of days in a non-leap year
	static const INT64 DaysPerYear = 365;
	// Number of days in 4 years
	static const INT64 DaysPer4Years = DaysPerYear * 4 + 1;
	// Number of days in 100 years
	static const INT64 DaysPer100Years = DaysPer4Years * 25 - 1;
	// Number of days in 400 years
	static const INT64 DaysPer400Years = DaysPer100Years * 4 + 1;

	// number of days from 1/1/0001 to 12/31/9999
	static const int DaysTo10000 = DaysPer400Years * 25 - 366;
	static const INT64 MinTicks = 0;
	static const INT64 MaxTicks = DaysTo10000 * TicksPerDay - 1;

	enum DatePart
	{
		DatePartYear = 0,
		DatePartDayOfYear = 1,
		DatePartMonth = 2,
		DatePartDay = 3,
	};

    static int DaysToMonth365[];
    static int DaysToMonth366[];

    INT64	m_lTicks;
    long	m_lTimezone;		// Difference in minutes between local time and UTC.
};

////////////////////////////////////////////////////////////////////////////////
// TimeSpan

/**
 * Initializes a zero BFX::TimeSpan instance.
 */
inline TimeSpan::TimeSpan()
{
	m_lTicks = 0;
}

/**
 * Initializes a new BFX::TimeSpan instance to the specified of time span value.
 * @param lTime The time span value based on milliseconds.
 */
inline TimeSpan::TimeSpan(INT64 lTime)
{
	m_lTicks = lTime;
}

/**
 * The copy constructor initializes a new BFX::TimeSpan instance to the others.
 * @param ts
 */
inline TimeSpan::TimeSpan(const TimeSpan& ts)
{
	m_lTicks = ts.m_lTicks;
}

/**
 * Gets a value that represents the number of complete days.
 * @return The number of complete 24-hour days in the time span. This value may be negative if the time span is
 * 		negative.
 */
inline int TimeSpan::GetDays() const
{
	return (int)(m_lTicks / TicksPerDay);
}

/**
 * Gets a value that represents the number of hours in the current day.
 * @return The number of hours in the current day (-23 through 23).
 */
inline int TimeSpan::GetHours() const
{
	return (int)((m_lTicks / TicksPerHour) % 24);
}

/**
 * Gets a value that represents the number of minutes in the current hour.
 * @return The number of minutes in the current hour (-59 through 59).
 */
inline int TimeSpan::GetMinutes() const
{
	return (int)((m_lTicks / TicksPerMinute) % 60);
}

/**
 * Gets a value that represents the number of seconds in the current minute.
 * @return The number of seconds in the current minute (-59 through 59).
 */
inline int TimeSpan::GetSeconds() const
{
	return (int)((m_lTicks / TicksPerSecond) % 60);
}

/**
 * Gets a value that represents the number of milliseconds  in the current seconds.
 * @return the number of milliseconds in the current second (-1000 through 1000).
 */
inline int TimeSpan::GetMilliseconds() const
{
	return (int)((m_lTicks / TicksPerMillisecond) % 1000);
}

/**
 * Gets a value that represents the total number of complete hours.
 * @return The total number of complete hours.
 */
inline INT64 TimeSpan::GetTotalHours() const
{
	return (m_lTicks / TicksPerHour);
}

/**
 * Gets a value that represents the total number of complete minutes.
 * @return The total number of complete minutes.
 */
inline INT64 TimeSpan::GetTotalMinutes() const
{
	return (m_lTicks / TicksPerMinute);
}

/**
 * Gets a value that represents the total number of complete seconds.
 * @return The total number of complete seconds.
 */
inline INT64 TimeSpan::GetTotalSeconds() const
{
	return (m_lTicks / TicksPerSecond);
}

/**
 * Gets a value that represents the total number of complete milliseconds.
 * @return The total number of complete milliseconds.
 */
inline INT64 TimeSpan::GetTotalMilliseconds() const
{
	return (m_lTicks / TicksPerMillisecond);
}

//
// Operators
//

/**
 * The assign constructor to sets the specified BFX::TimeSpan instance to this instance.
 * @param ts The BFX::TimeSpan instance to be set.
 * @return The reference of this instance.
 */
inline TimeSpan& TimeSpan::operator =(const TimeSpan& ts)
{
	m_lTicks = ts.m_lTicks;
	return (*this);
}

/**
 * Adds the specified BFX::TimeSpan instance to this instance.
 * @param ts The BFX::TimeSpan instance to be add.
 * @return The result BFX::TimeSpan instance.
 */
inline TimeSpan& TimeSpan::operator +=(const TimeSpan& ts)
{
	m_lTicks += ts.m_lTicks;
	return (*this);
}

/**
 * Subtracts the specified TimeSpan to this instance.
 * @param ts The BFX::TimeSpan instance to be subtract.
 * @return The result BFX::TimeSpan instance.
 */
inline TimeSpan& TimeSpan::operator -=(const TimeSpan& ts)
{
	m_lTicks -= ts.m_lTicks;
	return (*this);
}

/**
 * Adds two specified BFX::TimeSpan instances.
 * @param ts The another specified BFX::TimeSpan instance.
 * @return The result BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::operator +(const TimeSpan& ts)
{
	return TimeSpan(m_lTicks + ts.m_lTicks);
}

/**
 * Subtracts the current TimeSpan instance from another specified TimeSpan instance.
 * @param ts The another BFX::TimeSpan instance.
 * @return The result BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::operator -(const TimeSpan& ts)
{
	return TimeSpan(m_lTicks - ts.m_lTicks);
}

/**
 * Tests whether two BFX::TimeSpan instances are equal.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the values are equal; otherwise, false.
 */
inline bool TimeSpan::operator ==(const TimeSpan& ts) const
{
	return (m_lTicks == ts.m_lTicks);
}

/**
 * Tests whether two BFX::TimeSpan instances are not equal.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the values are not equal; otherwise, false.
 */
inline bool TimeSpan::operator !=(const TimeSpan& ts) const
{
	return (m_lTicks != ts.m_lTicks);
}

/**
 * Tests whether a specified TimeSpan is greater than another specified TimeSpan.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the current value is greater than the value of ts; otherwise, false.
 */
inline bool TimeSpan::operator >(const TimeSpan& ts) const
{
	return (m_lTicks > ts.m_lTicks);
}

/**
 * Tests whether a specified BFX::TimeSpan instance is greater than or equal to another specified BFX::TimeSpan
 * instance.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the current value is greater than or equal to the value of ts; otherwise, false.
 */
inline bool TimeSpan::operator >=(const TimeSpan& ts) const
{
	return (m_lTicks >= ts.m_lTicks);
}

/**
 * Tests whether a specified BFX::TimeSpan instance is less than another specified BFX::TimeSpan instance.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the current value is less than the value of ts; otherwise, false.
 */
inline bool TimeSpan::operator <(const TimeSpan& ts) const
{
	return (m_lTicks < ts.m_lTicks);
}

/**
 * Tests whether a specified BFX::TimeSpan instance is less than or equal to another specified BFX::TimeSpan
 * instance.
 * @param ts The another BFX::TimeSpan instance.
 * @return True if the current value is less than or equal to the value of ts; otherwise, false.
 */
inline bool TimeSpan::operator <=(const TimeSpan& ts) const
{
	return (m_lTicks <= ts.m_lTicks);
}

//
// Static constructors
//

/**
 * Represents the zero BFX::TimeSpan value.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::Zero()
{
	return TimeSpan();
}

/**
 * Gets a BFX::TimeSpan instance that represents a specified number of days.
 * @param lDays A number of days.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::FromDays(INT64 lDays)
{
	return Interval(lDays, TicksPerDay);
}

/**
 * Gets a BFX::TimeSpan instance that represents a specified number of hours.
 * @param lHours A number of hours.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::FromHours(INT64 lHours)
{
	return Interval(lHours, TicksPerHour);
}

/**
 * Gets a BFX::TimeSpan instance that represents a specified number of minutes.
 * @param lMinutes A number of minutes.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::FromMinutes(INT64 lMinutes)
{
	return Interval(lMinutes, TicksPerMinute);
}

/**
 * Gets a BFX::TimeSpan instance that represents a specified number of seconds.
 * @param lSeconds A number of seconds.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::FromSeconds(INT64 lSeconds)
{
	return Interval(lSeconds, TicksPerSecond);
}

/**
 * Gets a BFX::TimeSpan instance that represents a specified number of milliseconds.
 * @param lMilliseconds A number of milliseconds.
 * @return The BFX::TimeSpan instance.
 */
inline TimeSpan TimeSpan::FromMilliseconds(INT64 lMilliseconds)
{
	return Interval(lMilliseconds, TicksPerMillisecond);
}

inline TimeSpan TimeSpan::Interval(INT64 value, INT64 iScale)
{
	double millis = (value * iScale) + (value >= 0 ? 0.5 : -0.5);
	BFX_ASSERT(millis > LONG_LONG_MIN && millis < LONG_LONG_MAX);
	return TimeSpan((INT64) millis);
}

inline INT64 TimeSpan::TimeToTicks(int nHour, int nMinute, int nSecond)
{
	// totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31,
	// which is less than 2^44, meaning we won't overflow totalSeconds.
    INT64 lTotalSeconds = (INT64)nHour * 3600 + (INT64)nMinute * 60 + (INT64)nSecond;
	BFX_ENSURE(lTotalSeconds >= (LONG_LONG_MIN / TicksPerSecond) && lTotalSeconds <= (LONG_LONG_MAX / TicksPerSecond));

    return (lTotalSeconds * TicksPerSecond);
}

////////////////////////////////////////////////////////////////////////////////
// Time

/**
 * Initializes a new instance of the BFX::Time of current time.
 */
inline Time::Time()
{
	m_lTimezone = Time::GetSysTimeZone();
	m_lTicks = Time::GetSysUtcTicks() - (m_lTimezone * TicksPerSecond);
}

/**
 * Initializes a new instance of the BFX::Time with specified ticks.
 * @param ticks
 */
inline Time::Time(INT64 ticks)
{
	m_lTicks = __CLAMP(ticks, MinTicks, MaxTicks);
	m_lTimezone = Time::GetSysTimeZone();
}

/**
 * Initializes a new instance of the BFX::Time with specified ticks, local time-zone.
 * @param ticks
 * @param lTimezone
*/
inline Time::Time(INT64 ticks, long lTimezone)
{
	m_lTicks = __CLAMP(ticks, MinTicks, MaxTicks);
	m_lTimezone = lTimezone;
}

/**
 * Initializes a new instance of the BFX::Time with the specified year, month, and day.
 * @param nYear
 * @param nMonth
 * @param nDay
 */
inline Time::Time(int nYear, int nMonth, int nDay)
{
	m_lTicks = TimeToTicks(nYear, nMonth, nDay, 0, 0, 0);
	m_lTimezone = Time::GetSysTimeZone();
}

/**
 * Initializes a new instance of the BFX::Time with the specified year, month, day, and time-zone.
 * @param nYear
 * @param nMonth
 * @param nDay
 * @param lTimezone
 */
inline Time::Time(int nYear, int nMonth, int nDay, long lTimezone)
{
	m_lTicks = TimeToTicks(nYear, nMonth, nDay, 0, 0, 0);
	m_lTimezone = lTimezone;

}

/**
 * Initializes a new instance of the BFX::Time with the specified year, month, day, hour, minute, and second.
 * @param nYear
 * @param nMonth
 * @param nDay
 * @param nHour
 * @param nMinute
 * @param nSecond
 */
inline Time::Time(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond)
{
	m_lTicks = TimeToTicks(nYear, nMonth, nDay, nHour, nMinute, nSecond);
	m_lTimezone = Time::GetSysTimeZone();
}

/**
 * Initializes a new instance of the BFX::Time with the specified year, month, day, hour, minute, second, and time-zone.
 * @param nYear
 * @param nMonth
 * @param nDay
 * @param nHour
 * @param nMinute
 * @param nSecond
 * @param lTimezone
 */
inline Time::Time(int nYear, int nMonth, int nDay, int nHour, int nMinute, int nSecond, long lTimezone)
{
	m_lTicks = TimeToTicks(nYear, nMonth, nDay, nHour, nMinute, nSecond);
	m_lTimezone = lTimezone;
}

/**
 * The copy constructor to initializes a new instance of the BFX::Time from other instance.
 * @param time
 */
inline Time::Time(const Time& time)
{
	m_lTicks = time.m_lTicks;
	m_lTimezone = time.m_lTimezone;
}

/**
 * The destructor to destroys the BFX::Time instance.
 */
inline Time::~Time()
{
}

inline Time Time::MinValue()
{
	static Time s_min(MinTicks, 0);
	return s_min;
}

inline Time Time::MaxValue()
{
	static Time s_max(MaxTicks, 0);
	return s_max;
}

/**
 * Creates a BFX::Time instance that represents the current time.
 * @return the new instance of BFX::Time.
 */
inline Time Time::Now()
{
	return Time();
}

/**
 * Creates a BFX::Time instance that is set to the current time, expressed as the Coordinated Universal Time (UTC).
 * @return the new instance of BFX::Time.
 */
inline Time Time::UtcNow()
{
	return Time(GetSysUtcTicks(), 0);
}

/**
 * Gets a ticks value for the current BFX::Time instance.
 * @return The number of ticks that represent the date and time of this instance.
 */
inline INT64 Time::GetTicks() const
{
	return m_lTicks;
}

inline INT64 Time::GetUtcTicks() const
{
	INT64 lUtcTicks;
	if (m_lTicks <= MinTicks)
		lUtcTicks = MinTicks;
	else if  (m_lTicks >= MaxTicks)
		lUtcTicks = MaxTicks;
	else
		lUtcTicks = (m_lTicks + m_lTimezone * TicksPerSecond);
	return __CLAMP(lUtcTicks, MinTicks, MaxTicks);
}

/**
 * Gets the year component of the date represented by this instance.
 * @return
 */
inline int Time::GetYear() const
{
	return GetDatePart(DatePartYear);
}

/**
 * Gets the month of the year represented by this instance.
 * @return
 */
inline int Time::GetMonth() const
{
	return GetDatePart(DatePartMonth);
}

/**
 * Gets the day of the month represented by this instance.
 * @return
 */
inline int Time::GetDay() const
{
	return GetDatePart(DatePartDay);
}

/**
 * Gets the hour of the day represented by this instance.
 * @return
 */
inline int Time::GetHour() const
{
	return (int) ((m_lTicks / TicksPerHour) % 24);
}

/**
 * Gets the minute of the hour represented by this instance.
 * @return
 */
inline int Time::GetMinute() const
{
	return (int) ((m_lTicks / TicksPerMinute) % 60);
}

/**
 * Gets the second of the minute represented by this instance.
 * @return
 */
inline int Time::GetSecond() const
{
	return (int) ((m_lTicks / TicksPerSecond) % 60);
}

/**
 * Gets the millisecond of the second represented by this instance.
 * @return
 */
inline int Time::GetMillisecond() const
{
	return (int) ((m_lTicks / TicksPerMillisecond) % 1000);
}

/**
 * The assign constructor to sets this BFX::Time instance from other instance.
 * @param time
 * @return
 */
inline Time& Time::operator =(const Time& time)
{
	m_lTicks = time.m_lTicks;
	m_lTimezone = time.m_lTimezone;
	return (*this);
}

/**
 * Adds the this BFX::Time instance with specified BFX::TimeSpan instances.
 * @param ts
 * @return
 */
inline Time Time::operator +(const TimeSpan& ts) const
{
	return Time(m_lTicks + ts.m_lTicks);
}

/**
 * Subtracts the this BFX::Time instance with specified BFX::TimeSpan instances.
 * @param ts
 * @return
 */
inline Time Time::operator -(const TimeSpan& ts) const
{
	return Time(m_lTicks - ts.m_lTicks);
}

/**
 * Subtracts this BFX::Time instance with specified another BFX::Time instances.
 * @param time
 * @return
 */
inline TimeSpan Time::operator -(const Time& time) const
{
	if (this->m_lTimezone == time.m_lTimezone)
		return TimeSpan(m_lTicks - time.m_lTicks);
	else
		return TimeSpan(GetUtcTicks() - time.GetUtcTicks());
}

/**
 * Adds the specified BFX::TimeSpan instance to this BFX::Time instance.
 * @param ts
 * @return
 */
inline Time& Time::operator +=(const TimeSpan& ts)
{
	m_lTicks += ts.m_lTicks;
	m_lTicks = __CLAMP(m_lTicks, MinTicks, MaxTicks);
	return (*this);
}

/**
 * Subtracts the specified BFX::TimeSpan instance from this BFX::Time instance.
 * @param ts
 * @return
 */
inline Time& Time::operator -=(const TimeSpan& ts)
{
	m_lTicks -= ts.m_lTicks;
	m_lTicks = __CLAMP(m_lTicks, MinTicks, MaxTicks);
	return (*this);
}

/**
 * Tests whether this BFX::Time instance is equal to the another instance.
 * @param time
 * @return
 */
inline bool Time::operator ==(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks == time.m_lTicks;
	else
		return GetUtcTicks() == time.GetUtcTicks();
}

/**
 * Tests whether this BFX::Time instance is not equal to the another instance.
 * @param time
 * @return
 */
inline bool Time::operator !=(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks != time.m_lTicks;
	else
		return GetUtcTicks() != time.GetUtcTicks();
}

/**
 * Tests whether this BFX::Time instance is greater then the another instance.
 * @param time
 * @return
 */
inline bool Time::operator >(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks > time.m_lTicks;
	else
		return GetUtcTicks() > time.GetUtcTicks();
}

/**
 * Tests whether this BFX::Time instance is greater then or equal to the another instance.
 * @param time
 * @return
 */
inline bool Time::operator >=(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks >= time.m_lTicks;
	else
		return GetUtcTicks() >= time.GetUtcTicks();
}

/**
 * Tests whether this BFX::Time instance is less then the another instance.
 * @param time
 * @return
 */
inline bool Time::operator <(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks < time.m_lTicks;
	else
		return GetUtcTicks() < time.GetUtcTicks();
}

/**
 * Tests whether this BFX::Time instance is less then or equal to the another instance.
 * @param time
 * @return
 */
inline bool Time::operator <=(const Time& time) const
{
	if (m_lTimezone == time.m_lTimezone)
		return m_lTicks <= time.m_lTicks;
	else
		return GetUtcTicks() <= time.GetUtcTicks();
}

} /* namespace BFX */

#endif /* TIME_H_ */
